linux USB host驱动
USB设备注册过程
usb_add_hcd -> register_root_hub -> usb_new_device -> device_add(添加设备) ->
usb_device_match(驱动匹配) -> generic_probe -> usb_set_configuration -> device_add(添加接口) ->
usb_device_match(ID 匹配) -> usb接口驱动的probe
USB初始化
usb_int
usb_int初始化整个usb系统的基础部分
- 注册USB总线
bus_register(&usb_bus_type); - 注册usbfs驱动
usb_register(&usbfs_driver); - 注册usb hub驱动
usb_hub_init -> usb_register(&hub_driver) - 注册通用设备驱动
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)
host总线初始化
以msm ehci为例
初始化echi驱动数据结构
ehci_init_driver(&msm_hc_driver, &msm_overrides);使用ehci_hc_driver数据结构为基础
创建hcd
1
2hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
其中msm_hc_driver在上一步初始化,以ehci_hc_driver为基础
重点:hcd->self是一条usb总线
1 | struct usb_hcd { |
添加hcd到系统中
usb_add_hcd(hcd, hcd->irq, IRQF_SHARED)- 向usb系统中注册一条总线
usb_register_bus(&hcd->self)) - 创建一个USB设备,作为根hub
rhdev = usb_alloc_dev(NULL, &hcd->self, 0)
hcd->self.root_hub = rhdev
详见:usb设备创建 - 为该总线注册根hub
register_root_hub(hcd)
- 向usb系统中注册一条总线
根hub注册过程
获取根hub的描述信息
usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);向usb系统中添加了一个usb设备:usb_new_device (usb_dev);
该设备是上一步创建的根hub设备struct usb_device \usb_dev = hcd->self.root_hub;*
usb设备创建
usb_alloc_dev(struct usb_device parent,
struct usb_bus bus, unsigned port1)
设备类型:
1 | dev->dev.bus = &usb_bus_type; |
设备路径&设备名字:
根hub:很简单,路径为”0”, 名字直接是总线编号
dev->devpath[0] = ‘0’;
dev_set_name(&dev->dev, “usb%d”, bus->busnum);
普通设备
hub设备自身(父设备为根hub):路径为端口编号
snprintf(dev->devpath, sizeof dev->devpath, “%d”, port1);
普通设备(父设备为hub设备):路径为hub路径+端口编号
snprintf(dev->devpath, sizeof dev->devpath,”%s.%d”, parent->devpath, port1);
设备名字:总线编号 + 设备路径
dev_set_name(&dev->dev, “%d-%s”, bus->busnum, dev->devpath);
usb添加设备
int usb_new_device(struct usb_device *udev)
USB枚举设备
usb_enumerate_device(udev)
获取USB配置:usb_get_configuration(udev)显示usb设备信息
announce_device(udev);添加设备
device_add(&udev->dev)
重点:会触发probe创建endpoint设备
usb_create_ep_devs(&udev->dev, &udev->ep0, udev)1
2
3
4
5
6ep_dev->udev = udev;
ep_dev->dev.groups = ep_dev_groups;
ep_dev->dev.type = &usb_ep_device_type;
ep_dev->dev.parent = parent;
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
device_register(&ep_dev->dev);
usb probe过程
- 查找驱动
usb_device_match - usb设备probe:generic_probe
选择配置:usb_choose_configuration
设置配置:usb_set_configuration (重点) - usb接口probe:
配置id表:usb驱动的id_table
动态匹配(非常有用)usb_match_id(intf, usb_drv->id_table)
usb 动态匹配表
usb probe过程中,优先使用静态表(代码中写死,编译后不可更改),如果静态表中没有当前设备(usb 接口)则使用动态表
动态表由应用层写入
路径:/sys/bus/usb/driver/\
格式:\
usb 设置配置
usb_set_configuration
遍历当前配置的接口(通过usb_get_configuration从usb设备获取)
1 | intf->dev.bus = &usb_bus_type; |
遍历当前配置的接口
添加接口:device_add(&intf->dev)
重点:会触发probe
hub初始化过程
添加usb接口时(device_add)触发probe,如果接口是hub,则执行hub_probe
hub的匹配表:USB_CLASS_HUB=9
1
2
3
4
5
6
7
8
9
10
11
12static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR //指定产商的hub
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, //设备为hub
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, //接口为hub
.bInterfaceClass = USB_CLASS_HUB},
{ } /* Terminating entry */
};hub_probe
新建1个hub,配置hub(重点)1
2
3
4
5hub = kzalloc(sizeof(*hub), GFP_KERNEL)
...
INIT_WORK(&hub->events, hub_event);
usb_set_intfdata (intf, hub);
hub_configure(hub, endpoint)
hub_event是重点
配置hub
hub_configure(struct usb_hub hub, struct usb_endpoint_descriptor endpoint)
获取hub的描述
get_hub_descriptor(hdev, hub->descriptor)获取hub设备的状态
usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus)获取hub的状态
hub_hub_status(hub, &hubstatus, &hubchange)
get_hub_status(hub->hdev, &hub->status->hub)创建端口设备
1
2
3
4
5
6
7
8for (i = 0; i < maxchild; i++) {
ret = usb_hub_create_port_device(hub, i + 1);
if (ret < 0) {
dev_err(hub->intfdev,
"couldn't create port%d device.\n", i + 1);
break;
}
}1
2
3
4
5
6port_dev->dev.groups = port_dev_group;
port_dev->dev.type = &usb_port_device_type;
port_dev->dev.driver = &usb_port_driver;
dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
port1);
retval = device_register(&port_dev->dev);创建的端口在/sys/bus/usb/device/
下可见
hub事件处理
hub_event
处理hub下每个端口的事件
1 | for (i = 1; i <= hdev->maxchild; i++) { |
port_event
获取端口状态:hub_port_status(hub, port1, &portstatus, &portchange)
端口连接事件发生变化时,执行hub_port_connect_change
hub端口连接事件
hub_port_connect_change->hub_port_connect
端口下有设备,则先移除
1
2
3
4
5if (udev) {
if (hcd->usb_phy && !hdev->parent)
usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
usb_disconnect(&port_dev->child);
}创建一个usb设备
udev = usb_alloc_dev(hdev, hdev->bus, port1)- 初始化hub port
hub_port_init(hub, udev, port1, i);
获取设备描述:usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE) - 添加usb设备
status = usb_new_device(udev);